home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CD Exchange
/
CD Exchange - Volume 1.iso
/
d.t.p
/
utils
/
others
/
pcal
/
readfile.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-02-21
|
33KB
|
1,536 lines
/*
* readfile.c - Pcal routines concerned with reading and parsing the datefile
*
* Contents:
*
* cleanup
* clear_syms
* date_type
* do_define
* do_ifdef
* do_ifndef
* do_include
* do_undef
* enter_day_info
* find_sym
* find_year
* get_keywd
* get_month
* get_ordinal
* get_phase
* get_prep
* get_token
* get_weekday
* is_anyday
* is_fquarter
* is_fullmoon
* is_holiday
* is_lquarter
* is_newmoon
* is_weekday
* is_workday
* not_holiday
* not_weekday
* not_workday
* parse
* parse_date
* parse_ord
* parse_rel
* read_datefile
*
* Revision history:
*
* 4.3 AWR 10/25/91 Support moon phase wildcards and
* -Z flag (debug information)
*
* 4.2 AWR 10/03/91 Support "note/<n>" (user-selected
* notes box) as per Geoff Kuenning
*
* 09/30/91 Support "elif" in datefile
*
* 4.11 AWR 08/20/91 Support "nearest" keyword as per
* Andy Fyfe
*
* 4.0 AWR 02/19/91 Support negative ordinals
*
* AWR 02/06/91 Support expressions in "if{n}def"
*
* AWR 02/04/91 Support "even" and "odd" ordinals
* and ordinals > 5th; support "year"
*
* AWR 01/15/91 Extracted from pcal.c
*
*/
/*
* Standard headers:
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
/*
* Pcal-specific definitions:
*/
#include "pcaldefs.h"
#include "pcalglob.h"
#include "pcallang.h"
/*
* Macros:
*/
/* status codes returned by parse(), enter_day_info() */
#define PARSE_OK 0 /* successful date parse */
#define PARSE_INVDATE 1 /* nonexistent date */
#define PARSE_INVLINE 2 /* syntax error */
#define PARSE_NOMATCH 3 /* no match for wildcard */
/* codes for states in read_datefile() */
#define PROCESSING 0 /* currently processing datefile lines */
#define AWAITING_TRUE 1 /* awaiting first TRUE branch in "if{n}def" */
#define SKIP_TO_ENDIF 2 /* finished processing first TRUE branch */
/* append date to list; terminate list */
#define ADD_DATE(_m, _d, _y) if (1) { \
if (DEBUG(DEBUG_DATES)) \
FPR(stderr, "matched %d/%d/%d\n", \
_m, _d, _y); \
pdate->mm = _m, pdate->dd = _d, pdate++->yy = _y; \
} else
#define TERM_DATES pdate->mm = pdate->dd = pdate->yy = 0
/*
* Globals:
*/
static DATE dates[MAX_DATES+1]; /* array of date structures */
static char *pp_sym[MAX_PP_SYMS]; /* preprocessor defined symbols */
/*
* read_datefile - read and parse date file, handling preprocessor lines
*
* This is the main routine of this module. It calls getline() to read each
* non-null line (stripped of leading blanks and trailing comments), loadwords()
* to "tokenize" it, and get_token() to classify it as a preprocessor directive
* or "other". A switch{} statement takes the appropriate action for each
* token type; "other" lines are further classified by parse() (q.v.) which
* calls parse_date() (q.v.) to parse date entries and enter them in the data
* structure (as described in pcaldefs.h).
*
*/
#ifdef PROTOS
void read_datefile(FILE *fp,
char *filename)
#else
void read_datefile(fp, filename)
FILE *fp; /* file pointer (assumed open) */
char *filename; /* file name (for error messages) */
#endif
{
static int file_level = 0;
int if_level = 0;
int line = 0;
int pptype, extra, ntokens, save_year, expr;
int (*pfcn)();
char *ptok;
char **pword;
char msg[STRSIZ], incpath[STRSIZ];
/* stack for processing nested "if{n}defs" - required for "elif" */
struct {
int state; /* PROCESSING, AWAITING_TRUE, SKIP_TO_ENDIF */
int else_ok; /* is "elif" or "else" legal at this point? */
} if_state[MAX_IF_NESTING+1];
if (fp == NULL) /* whoops, no date file */
return;
/* note that there is no functional limit on file nesting; this is
* mostly to catch infinite loops (e.g., a includes b, b includes a)
*/
if (++file_level > MAX_FILE_NESTING) {
ERR(E_FILE_NESTING);
exit(EXIT_FAILURE);
}
save_year = curr_year; /* save default year */
if_state[0].state = PROCESSING; /* set up initial state */
if_state[0].else_ok = FALSE;
/* read lines until EOF */
while (getline(fp, lbuf, &line)) {
if (DEBUG(DEBUG_PP)) {
FPR(stderr, "%s (%d)", filename, line);
if (if_state[if_level].state == PROCESSING)
FPR(stderr, ": '%s'", lbuf);
FPR(stderr, "\n");
}
ntokens = loadwords(words, lbuf); /* split line into tokens */
pword = words; /* point to the first */
/* get token type and pointers to function and name */
pptype = get_token(*pword++);
pfcn = pp_info[pptype].pfcn;
ptok = pp_info[pptype].name;
switch (pptype) {
case PP_DEFINE:
case PP_UNDEF:
if (if_state[if_level].state == PROCESSING)
(void) (*pfcn)(*pword);
extra = ntokens > 2;
break;
case PP_ELIF:
if (!if_state[if_level].else_ok) {
ERR(E_ELIF_ERR);
break;
}
/* if a true expression has just been processed, disable
* processing and skip to endif; if no true expression
* has been found yet and the current expression is
* true, enable processing
*/
switch (if_state[if_level].state) {
case PROCESSING:
if_state[if_level].state = SKIP_TO_ENDIF;
break;
case AWAITING_TRUE:
copy_text(lbuf, pword); /* reconstruct string */
if ((expr = (*pfcn)(lbuf)) == EXPR_ERR) {
ERR(E_EXPR_SYNTAX);
expr = FALSE;
}
if (expr)
if_state[if_level].state = PROCESSING;
break;
}
extra = FALSE;
break;
case PP_ELSE:
if (!if_state[if_level].else_ok) {
ERR(E_ELSE_ERR);
break;
}
/* if a true condition has just been processed, disable
* processing and skip to endif; if no true condition
* has been found yet, enable processing
*/
switch (if_state[if_level].state) {
case PROCESSING:
if_state[if_level].state = SKIP_TO_ENDIF;
break;
case AWAITING_TRUE:
if_state[if_level].state = PROCESSING;
break;
}
/* subsequent "elif" or "else" forbidden */
if_state[if_level].else_ok = FALSE;
extra = ntokens > 1;
break;
case PP_ENDIF:
if (if_level < 1) {
ERR(E_END_ERR);
break;
}
if_level--;
extra = ntokens > 1;
break;
case PP_IFDEF:
case PP_IFNDEF:
/* "if{n}def"s nested too deeply? */
if (++if_level > MAX_IF_NESTING) {
ERR(E_IF_NESTING);
exit(EXIT_FAILURE);
break;
}
/* if processing enabled at outer level, evaluate
* expression and enable/disable processing for
* following clause; if not, skip to matching endif
*/
if (if_state[if_level-1].state == PROCESSING) {
copy_text(lbuf, pword); /* reconstruct string */
if ((expr = (*pfcn)(lbuf)) == EXPR_ERR) {
ERR(E_EXPR_SYNTAX);
expr = FALSE;
}
if_state[if_level].state = expr ? PROCESSING :
AWAITING_TRUE;
} else
if_state[if_level].state = SKIP_TO_ENDIF;
if_state[if_level].else_ok = TRUE;
extra = FALSE;
break;
case PP_INCLUDE:
if (if_state[if_level].state == PROCESSING)
do_include(mk_path(incpath, filename), *pword);
extra = ntokens > 2;
break;
case PP_OTHER: /* none of the above - parse as date */
if (if_state[if_level].state == PROCESSING) {
switch (parse(words, filename)) {
case PARSE_INVDATE:
ERR(E_INV_DATE);
break;
case PARSE_INVLINE:
ERR(E_INV_LINE);
break;
case PARSE_NOMATCH:
ERR(E_NO_MATCH);
break;
}
}
extra = FALSE;
break;
} /* end switch */
if (extra) { /* extraneous data? */
sprintf(msg, E_GARBAGE, ptok);
ERR(msg);
}
} /* end while */
if (if_level > 0)
FPR(stderr, E_UNT_IFDEF, progname, filename);
file_level--;
curr_year = save_year; /* restore default year */
}
/*
* Routines to free allocated data (symbol table and data structure)
*/
/*
* clear_syms - clear and deallocate the symbol table
*/
#ifdef PROTOS
void clear_syms(void)
#else
void clear_syms()
#endif
{
int i;
for (i = 0; i < MAX_PP_SYMS; i++)
if (pp_sym[i]) {
free(pp_sym[i]);
pp_sym[i] = NULL;
}
}
/*
* cleanup - free all allocated data
*/
#ifdef PROTOS
void cleanup(void)
#else
void cleanup()
#endif
{
int i, j;
year_info *py, *pny;
month_info *pm;
day_info *pd, *pnd;
for (py = head; py; py = pny) { /* main data structure */
pny = py->next;
for (i = 0;